﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using PECommon;
using PEProtocol;
using PEUtils;
using PNet;
namespace BattleServer
{
    public class BattleAccessToken
    {
        public int UID;
        public string AccessToken; //服务端生成的MD5Token
        public RoleData RoleData;  //该UID的Token所对应的角色数据
        public DateTime VaildTime; //Token生效的有效时间

    }


    public class LoginNet : ILogic
    {
        /// <summary>
        /// 缓存战斗服Token相关数据 key:Acct 
        /// </summary>
        private Dictionary<string, BattleAccessToken> mBattleTokenDic = new Dictionary<string, BattleAccessToken>();
        /// <summary>
        /// 缓存登录账号和对应的Token
        /// </summary>
        private readonly Dictionary<string, LoginToken> mAcct2TokenDic = new Dictionary<string, LoginToken>();
        /// <summary>
        /// 缓存登录服务器下发的模拟数据，方便在Battle战斗服中去使用
        /// </summary>
        private readonly Dictionary<string,List<RoleData>> mAcct2RoleDataDic = new Dictionary<string, List<RoleData>>();
        private int mTempUID = 1001;
        public int TempUID { get => mTempUID++; set => mTempUID = value; }

        private readonly Dictionary<CMD,Action<LoginPack>> mMsgPackDic = new Dictionary<CMD,Action<LoginPack>>();
        private ConcurrentQueue<LoginPack> mMsgQueue = new ConcurrentQueue<LoginPack>();
        private IOCPNet<LoginToken, NetMsg> mLoginNet;

        public void Awake()
        {
            IOCPTool.LogFunc = (msg) => PELog.Log(msg);
            IOCPTool.WarningFunc = (msg) => PELog.Warn(msg);
            IOCPTool.ErrorFunc = (msg) => PELog.Error(msg);
            IOCPTool.ColorLogFunc = (color, msg) => { PELog.ColorLog((PEUtils.LogColor)color, msg); };
            mLoginNet = new IOCPNet<LoginToken, NetMsg>();
            mLoginNet.StartAsServer("192.168.0.100", 17888, 5000);

            AddServerHandle(CMD.OnClient2LoginConnected, OnClient2LoginConnected);
            AddServerHandle(CMD.OnClient2LoginDisconnected, OnClient2LoginDisconnected);
            AddServerHandle(CMD.ReqLogin, ReqAcctLogin);
            AddServerHandle(CMD.ReqRoleToken, ReqRoleToken);
        }

        public void Update()
        {
            while (!mMsgQueue.IsEmpty)
            {
                if (mMsgQueue.TryDequeue(out LoginPack? pack))
                {
                    if (mMsgPackDic.ContainsKey(pack.Msg.CMD))
                    {
                        mMsgPackDic[pack.Msg.CMD]?.Invoke(pack);
                    }
                    
                }
                
            }
           
        }

        public void Destory()
        {
            mLoginNet.CloseServer();
            mMsgPackDic.Clear();
            mMsgQueue.Clear();
            mLoginNet = null;
        }

        /// <summary>
        /// 角色请求生成Battle的Token
        /// </summary>
        /// <param name="pack"></param>
        public void ReqRoleToken(LoginPack pack)
        {
            ReqRoleToken req = pack.Msg.ReqRoleToken;
            NetMsg msg = new NetMsg();
            msg.CMD = CMD.RspRoleToken;
            msg.RspRoleToken = new RspRoleToken();
            RoleData roleData = null;
            if (mAcct2RoleDataDic.TryGetValue(req.Acct, out List<RoleData>? roleDatas))
            {
                for (int i = 0; i < roleDatas.Count; i++)
                {
                    if (roleDatas[i].UID == req.SelectUID)
                    {
                        roleData = roleDatas[i];
                        break;
                    }
                }
                if (!mBattleTokenDic.TryGetValue(req.Acct, out BattleAccessToken? token))
                {
                    token = new BattleAccessToken();
                    token.AccessToken = PECalcTool.GetMD5Hash(req.SelectUID.ToString() + DateTime.Now);
                    token.UID = req.SelectUID;

                    token.VaildTime = DateTime.Now.AddMinutes(5);
                    mBattleTokenDic.Add(req.Acct, token);
                    msg.RspRoleToken.Token = token.AccessToken;
                    msg.RspRoleToken.BattleIP = "192.168.0.100";
                    msg.RspRoleToken.BattlePort = 17688;
                }
            }
            else
            {
                msg.EID = ErrorCode.Accct_Not_Exist;
            }
            pack.Token.SendMsg(msg);
        }

        public void AddServerMsg(LoginPack pack)
        {
            mMsgQueue.Enqueue(pack);
        }

        public void AddServerHandle(CMD cmd, Action<LoginPack> action)
        {
            if (!mMsgPackDic.ContainsKey(cmd))
            {
                mMsgPackDic.Add(cmd, action);
            }
            else
            {
                this.LogYellow($"The dictionary is alreay exist this key:[{cmd}]");
            }
            
        }

        private void ReqAcctLogin(LoginPack pack)
        {
            ReqAcctLogin reqLogin = pack.Msg.ReqAcctLogin;
            NetMsg rspLogin = new NetMsg();
            rspLogin.CMD = CMD.RspLogin;
            if (!mAcct2TokenDic.ContainsKey(reqLogin.Acct))
            {
                mAcct2TokenDic.Add(reqLogin.Acct, pack.Token);
                //TODO:调用SDK登录，这里假设验证通过
            }
            else
            {
                rspLogin.EID = ErrorCode.Acct_Online_Login;
            }
            pack.Token.SendMsg(rspLogin);

            if (rspLogin.EID == ErrorCode.None)
            {
                pack.Token.SendMsg(new NetMsg()
                {
                    CMD = CMD.NtfEnterStage,
                    NtfEnterStage = new NtfEnterStage() { StageID = 2 }
                });

            }

            if (rspLogin.EID == ErrorCode.None)
            {
              
                if (!mAcct2RoleDataDic.TryGetValue(reqLogin.Acct, out List<RoleData>? roleDatas))
                {
                    roleDatas = new List<RoleData>()
                        {
                            new RoleData()
                            {
                                UID = TempUID, //临时模拟ID
                                NickName = $"{reqLogin.Acct}_{TempUID}",
                                PosX = 1, PosY = 1,
                                DirX = 0, DirY = 0,
                                LastRid = PECalcTool.GetWorld(1,101),
                                LastTID = 0,

                                UnitID = 101,
                                Level = 1,
                                Exp = 100,
                            },
                            new RoleData()
                            {
                                UID = TempUID, //临时模拟ID
                                NickName = $"{reqLogin.Acct}_{TempUID}",
                                PosX = 1, PosY = 1,
                                DirX = 0, DirY = 0,
                                LastRid = PECalcTool.GetWorld(1,101),
                                LastTID = 0,

                                UnitID = 101,
                                Level = 3,
                                Exp = 300,
                            },
                        };
                    mAcct2RoleDataDic.Add(reqLogin.Acct, roleDatas);
                }
                NetMsg msg = new NetMsg()
                {
                    CMD = CMD.NtfRoleDatas,
                    EID = pack.Msg.EID,
                    NtfRoleDatas = new NtfRoleDatas { RoleDatas= roleDatas },
                };
                pack.Token.SendMsg(msg);
            }

        }

        private void OnClient2LoginDisconnected(LoginPack pack)
        {
            this.LogGreen($"Pack tokenID:{pack.Token.TokenID} client disconnected!");
        }

        private void OnClient2LoginConnected(LoginPack pack)
        {
            this.LogGreen($"Pack tokenID:{pack.Token.TokenID} client connected!");
        }

       
    }

    public class LoginPack
    {
        public NetMsg Msg;
        public LoginToken Token;

        public LoginPack(NetMsg msg, LoginToken token)
        {
            this.Msg = msg;
            this.Token = token;
        }
    }
}
